/**
 ******************************************************************************
 * @file           : bsp_oled.c
 * @brief          : OLED Display Driver (STM32F4xx)
 ******************************************************************************
 */

#include "./Devices/OLED/bsp_oled.h"
#include "./Devices/OLED/bsp_oled_config.h"
#include "./BSP/IIC/bsp_iic.h"
#include <string.h>

static uint8_t sg_oled_buffer[OLED_HEIGHT / 8][OLED_WIDTH];

static void oled_write_cmd(uint8_t cmd)
{
    uint8_t data[2] = {0x00, cmd};
    iic_write_bytes(OLED_I2C_ADDR, 0x00, data, 2);
}

static void oled_write_data(uint8_t data)
{
    uint8_t buf[2] = {0x40, data};
    iic_write_bytes(OLED_I2C_ADDR, 0x00, buf, 2);
}

uint8_t oled_init(void)
{
    oled_write_cmd(0xAE);  /* Display OFF */
    oled_write_cmd(0xD5);  /* Set clock */
    oled_write_cmd(0x80);
    oled_write_cmd(0xA8);  /* Set multiplex */
    oled_write_cmd(0x3F);
    oled_write_cmd(0xD3);  /* Set display offset */
    oled_write_cmd(0x00);
    oled_write_cmd(0x40);  /* Set start line */
    oled_write_cmd(0x8D);  /* Enable charge pump */
    oled_write_cmd(0x14);
    oled_write_cmd(0x20);  /* Set memory mode */
    oled_write_cmd(0x02);
    oled_write_cmd(0xA1);  /* Set segment remap */
    oled_write_cmd(0xC8);  /* Set COM output scan direction */
    oled_write_cmd(0xDA);  /* Set COM pins */
    oled_write_cmd(0x12);
    oled_write_cmd(0x81);  /* Set contrast */
    oled_write_cmd(0xCF);
    oled_write_cmd(0xD9);  /* Set precharge */
    oled_write_cmd(0xF1);
    oled_write_cmd(0xDB);  /* Set VCOMH */
    oled_write_cmd(0x40);
    oled_write_cmd(0xAF);  /* Display ON */
    
    oled_clear();
    log_i("OLED initialized");
    return 0;
}

void oled_deinit(void)
{
    oled_write_cmd(0xAE);
}

void oled_clear(void)
{
    memset(sg_oled_buffer, 0, sizeof(sg_oled_buffer));
    oled_refresh();
}

void oled_display_on(void)
{
    oled_write_cmd(0xAF);
}

void oled_display_off(void)
{
    oled_write_cmd(0xAE);
}

void oled_show_char(uint8_t x, uint8_t y, char ch)
{
    if (x >= OLED_WIDTH || y >= OLED_HEIGHT)
    {
        return;
    }
    
    /* 简单实现：只标记位置 */
    sg_oled_buffer[y / 8][x] = 0xFF;
}

void oled_show_string(uint8_t x, uint8_t y, const char *str)
{
    if (str == NULL)
    {
        return;
    }
    
    while (*str)
    {
        oled_show_char(x, y, *str);
        x += 8;
        str++;
    }
}

void oled_refresh(void)
{
    for (int i = 0; i < OLED_HEIGHT / 8; i++)
    {
        oled_write_cmd(0xB0 + i);
        oled_write_cmd(0x00);
        oled_write_cmd(0x10);
        
        for (int j = 0; j < OLED_WIDTH; j++)
        {
            oled_write_data(sg_oled_buffer[i][j]);
        }
    }
}
